/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 *
 * 知启蒙数据库映射（zhiqim_orm）在LGPL3.0协议下开源：https://www.zhiqim.com/gitcan/zhiqim/zhiqim_orm.htm
 *
 * This file is part of [zhiqim_orm].
 *
 * [zhiqim_orm] is free software: you can redistribute
 * it and/or modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * [zhiqim_orm] is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with [zhiqim_orm].
 * If not, see <http://www.gnu.org/licenses/>.
 */
package com.xygz.orm;

import com.xygz.orm.constants.ORMConstants;
import com.xygz.orm.enums.FormatType;

import java.sql.DatabaseMetaData;
import java.sql.SQLException;

/**
 * ORM服务需要配置的参数，如果是外部数据源的话则
 *
 * @version v1.0.0 @author xiyuan-lgz 2018-3-21 新建与整理
 */
@SuppressWarnings("all")
public class ORMParameter implements ORMConstants {
    
    // 必须两项
    private boolean isDefault;
    
    
    private String id;
    // 内部数据源 必填五项，外部可忽略
    
    /**
     * 数据库驱动
     */
    private String driver;
    
    /**
     * 数据库链接字符串
     */
    private String url;
    
    /**
     * 数据库链接用户名
     */
    private String username;
    
    /**
     * 数据库密码
     */
    private String password;
    
    // 事务级别，-1表示未配置取数据库本身
    
    /**
     * 配置事务级别
     */
    private int transactionIsolation = -1;
    
    // 常用配置三项
    
    /**
     * 连接池最小连接数
     */
    private int minPoolSize = 0;
    
    /**
     * 连接池最大连接数
     */
    private int maxPoolSize = 10;
    
    /**
     * 数据库连接保留时长, 默认=7001 秒， 最小：10 秒
     */
    private int maxKeepTime = 7001;
    
    // 连接时效两项
    
    /**
     * 数据库空闲时长, 默认=7001 秒， 最小：10 秒
     */
    private int maxIdleTime = 7001;
    
    // 密码类型
    
    private String passType = null;
    
    // 检查连接三项
    
    private boolean chkConnOnTimer = false;
    
    /**
     * 获取链接时是否检查链接
     */
    private boolean chkConnOnGet = false;
    
    /**
     * 释放链接是是否检查链接
     */
    private boolean chkConnOnRelease = false;
    
    /**
     * 链接检查时长 单位秒， 默认=60 秒，最小=5秒
     */
    private int chkDelay = 60;
    
    // 耗尽重试两项
    
    /**
     * 获取链接尝试次数，, 默认=5次， 最小：1 次
     */
    private int outOfConnRetryCount = 5;
    
    
    // SQL输出日志两项
    
    /**
     * 是否输出 insert和 update SQL
     */
    private boolean isUpdateSqlLog = false;
    
    /**
     * 是否输出 查询 SQL
     */
    private boolean isQuerySqlLog = false;
    
    
    /**
     * SQL 格式化 样式
     */
    private String formatType = FormatType.PREPARED.getCode();
    
    // sql文件表
//    private HashMap<String, Integer> sqlMap = new HashMap<>();
//    private HashMap<String, String> cacheMap = new HashMap<String, String>();
    
    
    /***********************************************************************************/
    // 构造函数
    /***********************************************************************************/
    
    /**
     * 空构造，然后手动设置参数
     */
    public ORMParameter(String id) {
        this.id = id;
    }
    
    public String getId() {
        return id;
    }
    
    public boolean isDefault() {
        return isDefault;
    }
    
    public void setDefault(boolean isDefault) {
        this.isDefault = isDefault;
    }
    
    /***********************************************************************************/
    // SQL文件表
    /***********************************************************************************/

//    public HashMapSV<Integer> getSqlConfig()
//    {
//        return sqlMap;
//    }
//
//    public void addSqlConfig(String key, String value)
//    {
//        int type = Z_SQL_FILE.equals(value)?Z_SQL_FILE_INT:
//                   Z_SQL_FOLDER.equals(value)?Z_SQL_FOLDER_INT:
//                   Z_SQL_CLASS.equals(value)?Z_SQL_CLASS_INT:
//                   Z_SQL_PACKAGE.equals(value)?Z_SQL_PACKAGE_INT:-1;
//
//        addSqlConfig(key, type);
//    }
//
//    public void addSqlConfig(String key, int type)
//    {
//        Asserts.notNull(key, _KEY_);
//        Asserts.as((type >= 0 && type <= 3)?null:"增加ORM的SQL配置["+key+"]的类型不正确");
//
//        switch (type)
//        {
//        case Z_SQL_FILE_INT:
//        {
//            Asserts.as(key.endsWith(Z_SQL_ENDSWITH)?null:"增加ORM的SQL配置["+key+"]必须以[.sql.xml]结尾的SQL配置文件名");
//
//            File file = new File(key);
//            Asserts.as((file.isFile() && file.canRead())?null:"增加ORM的SQL配置["+key+"]必须是文件并可读");
//            break;
//        }
//        case Z_SQL_FOLDER_INT:
//        {
//            File folder = new File(key);
//            Asserts.as((folder.isDirectory() && folder.canRead())?null:"增加ORM的SQL配置["+key+"]必须是文件夹并可读");
//            break;
//        }
//        case Z_SQL_CLASS_INT:
//        {
//            Asserts.as(key.endsWith(Z_SQL_ENDSWITH)?null:"增加ORM的SQL配置["+key+"]必须以[.sql.xml]结尾的SQL配置文件名");
//            Asserts.as(Resources.exists(ORMServer.class, key) ? null : "增加ORM的SQL配置["+key+"]必须是文件并可读");
//            break;
//        }
//        case Z_SQL_PACKAGE_INT:
//        {
//            Asserts.as(Resources.exists(ORMServer.class, key)?null:"增加ORM的SQL配置["+key+"]必须是存在");
//            break;
//        }
//        }
//
//        key = Systems.replacePropertyPath(key);
//        sqlMap.put(key, type);
//    }
    
    /***********************************************************************************/
    // Cache配置表
    /***********************************************************************************/
    
    
    /***********************************************************************************/
    /** 参数的设置和获取 ******************************************************************/
    /***********************************************************************************/
    
    
    public String getFormatType() {
        return formatType;
    }
    
    public ORMParameter setFormatType(String formatType) {
        FormatType type = FormatType.of(formatType);
        if (type != null) {
            this.formatType = type.getCode();
        }
        return this;
    }
    
    public boolean isUpdateSqlLog() {
        return isUpdateSqlLog;
    }
    
    public ORMParameter setUpdateSqlLog(boolean isUpdateSqlLog) {
        this.isUpdateSqlLog = isUpdateSqlLog;
        return this;
    }
    
    public boolean isQuerySqlLog() {
        return isQuerySqlLog;
    }
    
    public ORMParameter setQuerySqlLog(boolean isQuerySqlLog) {
        this.isQuerySqlLog = isQuerySqlLog;
        return this;
    }
    
    public String getDriver() {
        return driver;
    }
    
    public void setDriver(String driver) throws ClassNotFoundException {
        Class.forName(driver);
        this.driver = driver;
    }
    
    public String getUrl() {
        return url;
    }
    
    public ORMParameter setUrl(String url) {
        this.url = url;
        return this;
    }
    
    public String getUsername() {
        return username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    public String getPassword() {
        return password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    // public String getUsername() {
    //     return username;
    // }
    //
    // public ORMParameter setUser(String user) {
    //     this.username = user;
    //     return this;
    // }
    //
    // public String getPass() {
    //     return password;
    // }
    //
    // public void setPass(String pass) {
    //     this.password = pass;
    // }
    
    public String getPassType() {
        return passType;
    }
    
    public ORMParameter setPassType(String passType) {
        this.passType = passType;
        return this;
    }
    
    /**
     * Retrieves this <code>Connection</code> object's current
     * transaction isolation level.
     *
     * @return the current transaction isolation level, which will be one
     * of the following constants:
     * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
     * <code>Connection.TRANSACTION_READ_COMMITTED</code>,
     * <code>Connection.TRANSACTION_REPEATABLE_READ</code>,
     * <code>Connection.TRANSACTION_SERIALIZABLE</code>, or
     * <code>Connection.TRANSACTION_NONE</code>.
     * @throws SQLException if a database access error occurs
     *                      or this method is called on a closed connection
     * @see #setTransactionIsolation
     */
    public int getTransactionIsolation() {
        return transactionIsolation;
    }
    
    /**
     * Attempts to change the transaction isolation level for this
     * <code>Connection</code> object to the one given.
     * The constants defined in the interface <code>Connection</code>
     * are the possible transaction isolation levels.
     * <p>
     * <B>Note:</B> If this method is called during a transaction, the result
     * is implementation-defined.
     *
     * @param level one of the following <code>Connection</code> constants:
     *              <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>,
     *              <code>Connection.TRANSACTION_READ_COMMITTED</code>,
     *              <code>Connection.TRANSACTION_REPEATABLE_READ</code>, or
     *              <code>Connection.TRANSACTION_SERIALIZABLE</code>.
     *              (Note that <code>Connection.TRANSACTION_NONE</code> cannot be used
     *              because it specifies that transactions are not supported.)
     * @throws SQLException if a database access error occurs, this
     *                      method is called on a closed connection
     *                      or the given parameter is not one of the <code>Connection</code>
     *                      constants
     * @see DatabaseMetaData#supportsTransactionIsolationLevel
     * @see #getTransactionIsolation
     */
    public void setTransactionIsolation(Integer level) {
        this.transactionIsolation = level == null ? -1 : Math.max(-1, level);
    }
    
    public int getMinPoolSize() {
        return minPoolSize;
    }
    
    public void setMinPoolSize(int minPoolSize) {
        this.minPoolSize = Math.max(0, minPoolSize);
    }
    
    public int getMaxPoolSize() {
        return maxPoolSize;
    }
    
    public void setMaxPoolSize(int maxPoolSize) {
        this.maxPoolSize = Math.max(1, maxPoolSize);
    }
    
    /**
     * 数据库连接保留时长, 默认=7001 秒， 最小：60 秒
     *
     * @return Keep seconds
     */
    public int getMaxKeepTime() {
        return maxKeepTime;
    }
    
    
    /**
     * 数据库连接保留时长, 默认=7001 秒， 最小：60 秒
     *
     * @param maxKeepTime Keep seconds
     */
    public void setMaxKeepTime(Integer maxKeepTime) {
        if (maxKeepTime != null) {this.maxKeepTime = Math.max(10, maxKeepTime);}
    }
    
    public int getMaxIdleTime() {
        return maxIdleTime;
    }
    
    /**
     * 数据库空闲时长, 默认=7001 秒， 最小：10 秒
     *
     * @param maxIdleTime Keep seconds
     */
    public void setMaxIdleTime(Integer maxIdleTime) {
        if (maxIdleTime != null) {this.maxIdleTime = Math.max(10, maxIdleTime);}
    }
    
    public boolean isChkConnOnTimer() {
        return chkConnOnTimer;
    }
    
    public void setChkConnOnTimer(Boolean isChkConnOnTimer) {
        this.chkConnOnTimer = Boolean.TRUE.equals(isChkConnOnTimer);
    }
    
    public boolean isChkConnOnGet() {
        return chkConnOnGet;
    }
    
    public void setChkConnOnGet(Boolean isChkConnOnGet) {
        this.chkConnOnGet = Boolean.TRUE.equals(isChkConnOnGet);
    }
    
    public boolean isChkConnOnRelease() {
        return chkConnOnRelease;
    }
    
    public void setChkConnOnRelease(Boolean isChkConnOnRelease) {
        
        this.chkConnOnRelease = Boolean.TRUE.equals(isChkConnOnRelease);
        ;
    }
    
    public int getOutOfConnRetryCount() {
        return outOfConnRetryCount;
    }
    
    public void setOutOfConnRetryCount(Integer outOfConnRetryCount) {
        this.outOfConnRetryCount = outOfConnRetryCount == null ? 1 : Math.max(1, outOfConnRetryCount);
    }
    
    public int getChkDelay() {
        return chkDelay;
    }
    
    public void setChkDelay(Integer chkDelay) {
        this.chkDelay = chkDelay == null ? 60 : Math.max(5, chkDelay);
    }
}
